// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: donggu

#include "coin2/exchange/base/market/market_exchange_api.h"

#include <optional>
#include <string_view>

#include <fmt/format.h>
#include <boost/exception/diagnostic_information.hpp>

#include "coin2/base/string_util.h"

namespace coin2::exchange::base::market {

MarketExchangeApi MarketExchangeApi::FromString(const std::string_view& s) {
  const char* delims = ".";
  std::vector<std::string> vec;
  vec = Split(s, delims);
  CHECK_EQ_THROW(vec.size(), 3) << s;
  CHECK_GT_THROW(vec[2].size(), 0) << s;

  return MarketExchangeApi{
      StringToMarketType(vec[0]).value(),  // throw on nullopt
      StringToExchangeType(vec[1]).value(),
      vec[2]};
}

std::optional<MarketExchangeApi> MarketExchangeApi::FromStringNoThrow(const std::string_view& s) {
  try {
    return MarketExchangeApi::FromString(s);
  } catch (...) {
    LOG(ERROR) << s << "\n" << boost::current_exception_diagnostic_information();
    return {};
  }
}

MarketExchangeApi MarketExchangeApi::FromSnakeString(const std::string_view& s) {
  const char* delims = "_";
  std::vector<std::string> vec;
  vec = Split(s, delims);

  CHECK_EQ_THROW(vec.size(), 3);

  CHECK_GT_THROW(vec[0].size(), 0);
  CHECK_GT_THROW(vec[1].size(), 0);
  CHECK_GT_THROW(vec[2].size(), 0);

  vec[0][0] = std::toupper(vec[0][0]);  // spot => Spot
  vec[1][0] = std::toupper(vec[1][0]);  // okex => Okex

  return MarketExchangeApi{
      StringToMarketType(vec[0]).value(),  // may throw
      StringToExchangeType(vec[1]).value(),
      vec[2]};
}

std::optional<MarketExchangeApi> MarketExchangeApi::FromSnakeStringNoThrow(
    const std::string_view& s) {
  try {
    return MarketExchangeApi::FromSnakeString(s);
  } catch (...) {
    LOG(ERROR) << s << "\n" << boost::current_exception_diagnostic_information();
    return {};
  }
}

std::string MarketExchangeApi::String() const {
  // e.g. Spot.Huobi.v1
  return fmt::format("{}.{}.{}", MarketTypeToString(market), ExchangeTypeToString(exchange), api);
}

std::string MarketExchangeApi::SnakeString() const {
  // spot_huobi_v1
  // spot_okex_v3
  // futures_okex_v3
  std::string s =
      fmt::format("{}_{}_{}", MarketTypeToString(market), ExchangeTypeToString(exchange), api);
  StringToLowerInPlace(&s);
  return s;
}

}  // namespace coin2::exchange::base::market
